import time
import dbus

"""
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Library General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


  Boola 1.0.0 (Banshee control Over OLA)  
  (c) 2011 Chris Stranex. All Rights Reserved.   
"""

VERSION = "1.0.0";

debug = True; # Debug mode (can be activated with --debug)

# Constants
ADVANCED_MODE = 10; # 10 channel DMX mode (First 8 channels are the same as below)
WINAMP_MODE = 8; # Compatibility with MagicQ Winamp head. Not really required unless you need to repatch without moving things around
SHUFFLE_MODE_OFF = "off";
SHUFFLE_MODE_ON = "song"; # This could be changed to do album,artist,rating or score
REPEAT_MODE_OFF = 0;
REPEAT_MODE_ALL = 1;
REPEAT_MODE_ONE = 2;

class Banshee:

   _attributes = {
      'position': 0,
      'track': 0,
      'playlist': 1,
      'stopped': True,
   };
   
   def __init__(self):
      try:
         self.dbus();
      except dbus.exceptions.DBusException:
         raise RuntimeError("No instance of banshee is running with dbus.");

   def dbus(self):
      self.dbus = dbus.SessionBus();
      self.controller = self.dbus.get_object("org.bansheeproject.Banshee", "/org/bansheeproject/Banshee/PlaybackController");
      self.banshee = self.dbus.get_object("org.bansheeproject.Banshee", "/org/bansheeproject/Banshee/PlayerEngine");
      self.media = self.dbus.get_object("org.mpris.MediaPlayer2.banshee", "/org/mpris/MediaPlayer2");
      self.playlist = dbus.Interface(self.media,"org.mpris.MediaPlayer2.Playlists")

   def Play(self):
      position = self._attributes['position'];
      track = self._attributes['track'];
      playlist = self._attributes['playlist'];
      
      shuffleState = self.controller.GetShuffleMode();
      repeatState = self.controller.GetRepeatMode();
      self.controller.SetShuffleMode('off');
      self.controller.SetRepeatMode(0);

      self.setTrack(track);      
      
      # And play
      self.banshee.Play();
      
      # Set the states back to the old ones
      self.controller.SetShuffleMode(shuffleState);
      self.controller.SetRepeatMode(repeatState);
      
      self._attributes['stopped'] = False;
      if debug:
         print "Played";

   def Stop(self):
      self.banshee.Close();
      self._attributes['stopped'] = True;
      if debug:
         print "Closing";   
   
   def Pause(self):
      self.banshee.Pause();
      self._attributes['stopped'] = False;
      if debug:
         print "Pausing";
   
   def Continue(self):
      self.banshee.Play();
      self._attributes['stopped'] = False;
      if debug:
         print "Continuing";

   def setPlaylist(self,playlist):
      if debug:
         print "Playlist", playlist;
      try:
         self.playlist.ActivatePlaylist("/org/bansheeproject/Banshee/MusicLibrarySource/Playlists/PlaylistSource%i" % playlist);
      except dbus.exceptions.DBusException:
         return;
      self._attributes['playlist'] = playlist;
      
      # We were stopped. So don't play the song. Just "cue" it
      if self._attributes['stopped'] == True:
         self.Pause();

   # This is an incredibly ugly way of changing tracks
   # Fortunately the maximum number of tracks supported with DMX 256
   # The bad news is this takes about 3.5s(!) to get to 256 as there currently
   # is no known way to jump to a point in the playlist nor is there
   # a way to find out where you are in the playlist.
   def setTrack(self,track):
      if track < 0:
         return;

      a = time.time();
      shuffleState = self.controller.GetShuffleMode();
      self.controller.SetShuffleMode('off');
      
      self.setPlaylist(self._attributes['playlist']);
      # Count
      i=0;
      for i in range(0,track):
         self.controller.Next(False);
      self._attributes['track'] = i+1;

      self.controller.SetShuffleMode(shuffleState);

      # We were stopped. So don't play the song. Just "cue" it
      if self._attributes['stopped'] == True:
         self.Pause();

      if debug:
         b = time.time();
         sec = b-a;
         print "Next()",(i+1),"times. Took",sec;

   # Not supported
   def setPan(self,pan):
      if debug == True:
         print "Pan is not yet supported";

   # Dbus expects value in milliseconds
   # Value from MagicQ is a 16-bit integer in 25fps
   # ie: it can represent a value from 0 to 2621.44s (about 43 minutes)
   def setPosition(self,pos):
       if debug:
          print "Position", pos, "int", ((pos/25)*1000), "ms";
       self.banshee.SetPosition(dbus.UInt32((pos/25)*1000));
       self._attributes['position'] = pos;

   def setStopAfterCurrent(self,mode):
      self.controller.SetStopWhenFinished(mode);
      if debug:
         print "Stop After Current", mode;
   
   def setShuffle(self,mode):
      self.controller.SetShuffleMode(mode);
      if debug:
         print "Shuffle", mode;
   
   def setRepeat(self,mode):
      self.controller.SetRepeatMode(mode);
      if debug:
         print "Repeat", mode;
   
   def setVolume(self,volume):
      vol = int(float(volume)/255*100);
      if debug:
         print "Volume", vol;
      self.banshee.SetVolume(dbus.UInt16(vol));


